package org.btik.redstone.led.sender;


import org.btik.redstone.led.conf.Conf;
import org.slf4j.Logger;

import java.net.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;

import static org.btik.redstone.led.util.ByteUtil.getChars;
import static org.btik.redstone.led.util.ByteUtil.stringSize;

/**
 * @author lustre
 * @since 2022/11/28 22:15
 */
public class LightRawNbi extends Thread {
    private final Conf conf;
    private final Logger logger;
    private static final Intermediate STOP_FLAG = new Intermediate();
    private static final byte[] SPACE_4 = new byte[]{' ', ' ', ' ', ' '};

    static class Intermediate {
        byte[] sn;
        int val;

        final byte[] rawCommand = new byte[]{
                'L', 'N', 'B', 'I',         // schema:Light NBI nbi标识
                0,                          // type:raw 0-raw,1-json 命令类型
                // 暂且固定sn为mac长度为6字节， 12字符使得无需扩容当前命令
                12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // snLen int ,[sn] Array<char> sn长度和 sn
                // 以下为透传给设备的命令
                'i', 'd', ':', '0', '\n',   // id:0 无返回命令id为 0
                'o', 'p', ':', '1', '\n',   // op:1 操作码
                ' ', ' ', ' ', ' ', '\n'    // args 原本是空格分割此处为一个int
        };
    }

    private final ConcurrentLinkedQueue<Intermediate> cmdCache = new ConcurrentLinkedQueue<>();

    private final LinkedBlockingQueue<Intermediate> cmdQueue = new LinkedBlockingQueue<>();

    public void send(byte[] sn, int val) {
        Intermediate intermediate = cmdCache.poll();
        if (intermediate == null) {
            // 字段扩容
            intermediate = new Intermediate();
        }
        intermediate.sn = sn;
        intermediate.val = val;
        cmdQueue.add(intermediate);
    }

    @Override
    public void run() {
        Intermediate cmd;
        try (DatagramSocket client = new DatagramSocket(conf.getLocalPort())) {
            DatagramPacket datagramPacket = new DatagramPacket(new byte[0], 0);
            datagramPacket.setPort(conf.getPort());
            datagramPacket.setAddress(InetAddress.getByName(conf.getHost()));
            while ((cmd = cmdQueue.take()) != STOP_FLAG) {
                try {
                    System.arraycopy(cmd.sn, 0, cmd.rawCommand, 6, 12);
                    byte[] valArg = int2String(cmd.val);
                    // 变长值需要清除缓存
                    System.arraycopy(SPACE_4, 0, cmd.rawCommand, 28, 4);
                    System.arraycopy(valArg, 0, cmd.rawCommand, 28, valArg.length);
                    datagramPacket.setData(cmd.rawCommand);
                    client.send(datagramPacket);
                } catch (Exception ignored) {
                } finally {
                    cmdCache.add(cmd);
                }

            }
        } catch (SocketException | UnknownHostException e) {
            logger.error("load failed", e);
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            logger.error("exit by:", e);
        }


    }

    public static byte[] int2String(int i) {
        int size = stringSize(i);
        byte[] buf = new byte[size];
        getChars(i, size, buf);
        return buf;
    }

    public LightRawNbi(Conf conf, Logger logger) {
        super("LightRawNbi");
        this.conf = conf;
        this.logger = logger;
        for (int i = 0; i < 100; i++) {
            cmdCache.add(new Intermediate());
        }
    }

    public void shutDown() {
        cmdQueue.add(STOP_FLAG);
    }
}
